# -*- coding: utf-8 -*-
"""
梯度下降法模拟
Created on Wed Feb 14 18:46:51 2018

@author: Allen
"""
import numpy as np
import matplotlib.pyplot as plt

plot_x = np.linspace( -1, 6, 141 )
plot_y = ( plot_x - 2.5 ) ** 2 - 1

def j( theta ):
    '''
    求出纵坐标
    '''
    try:
        return ( theta - 2.5 ) ** 2 - 1
    except:
        return float( "inf" )

# 可视化 曲线
plt.plot( plot_x, j( plot_x ) )
plt.show()

def dj( theta ):
    '''
    求导数
    '''
    return 2 * ( theta - 2.5 )
 
theta = 0.0 # 设置 初始化 theta 
eta = 0.1 # 学习率
epsilon = 1e-8 # 设置一个区间，到达这一区间就表示下降完成

while True:
    # 使用梯度下降法
    last_theta = theta
    theta = theta - eta * dj( theta )
    
    # 需要注意的是：程序中浮点数的比较不能使用 “==”
    if np.absolute( j( theta ) - j( last_theta ) ) < 1e-8:
        break
    
print( theta )
print( j( theta ) )

theta = 0.0 # 设置 初始化 theta 
eta = 0.1 # 学习率
epsilon = 1e-8 # 设置一个区间，到达这一区间就表示下降完成
theta_history = [ theta ]
while True:
    # 使用梯度下降法
    last_theta = theta
    theta = theta - eta * dj( theta )
    theta_history.append( theta )
    # 需要注意的是：程序中浮点数的比较不能使用 “==”
    if np.absolute( j( theta ) - j( last_theta ) ) < 1e-8:
        break
    
print( theta )
print( j( theta ) )
print( theta_history )

# 观察 theta 下降的样子
plt.plot( plot_x, j( plot_x ) )
plt.plot( np.array(theta_history), j(  np.array(theta_history) ), color = "red", marker = "+" )
plt.show()

'''
需要注意的是：学习率的选取！
选取过大，将无法收敛
选取过小，收敛很慢
一般来说，学习率选择0.01，是一个比较保险的数字
'''
# 将以上代码进行封装
def gradient_descent( initial_theta, eta, n_iters = 1e4, epsilon = 1e-8 ):
    theta = initial_theta
    theta_history.append( theta )
    i_iter = 0
    while i_iter < n_iters:
        # 使用梯度下降法
        last_theta = theta
        theta = theta - eta * dj( theta )
        theta_history.append( theta )
        # 需要注意的是：程序中浮点数的比较不能使用 “==”
        if np.absolute( j( theta ) - j( last_theta ) ) < epsilon:
            break
        i_iter += 1
    return theta

def plot_theta_history():
    # 观察 theta 下降的样子
    plt.plot( plot_x, j( plot_x ) )
    plt.plot( np.array(theta_history), j(  np.array(theta_history) ), color = "red", marker = "+" )
    plt.show()
    
theta_history = []
gradient_descent( 0.0, 1.1 )


print( theta_history[-1] ) # 输出 nan